﻿module DrawStringHelper
open System;
open System.Collections.Generic;
open System.Linq;
open System.Text;
open System.Drawing;
open System.Drawing.Imaging;
open System.IO;

type OriOptions=
    |H //水平打印字符串
    |V //垂直打印字符串
//字符串水平位置
type Hor =
    |L //left
    |R //right
    |C //center
//字符串垂直位置
type Ver=
    |T //top
    |B //bottom
    |C //center

/// 把x 插到ls的间隙里面去    
let rec innerAdd  x ls=
    match ls with
    | a::b::t ->a::x::innerAdd x (b::t) 
    | a::[] -> [a]
    | [] -> []
///打印出来
let dump str =
    printf "%s" str
    str 
type String with
    member str.dump()=
        dump str
type SizeF with
    member sf.dump()=
        dump (String.Format("w:{0} h:{1}\r\n",sf.Width.ToString(),sf.Height.ToString()))
         
let toVertical (str:string)=
    str.ToCharArray()
    |> List.ofArray
    |> innerAdd '\n'
    |> List.fold(fun total c -> total+c.ToString()) ""
let toColor( str:string)=
    let r = str.Substring(1, 2);
    let g = str.Substring(3, 2);
    let b = str.Substring(5, 2);
    Color.FromArgb(
        Convert.ToInt32(r, 16),
        Convert.ToInt32(g, 16),
        Convert.ToInt32(b, 16));



//转换成01矩阵
let getFeatureMatrix (bp:Bitmap) (zeroColor:Color)=
    [|
        for y in 0..bp.Height-1 do
            let row =
                [|
                    for x in 0..bp.Width-1 do
                        let c = bp.GetPixel(x,y)
                        if  c.R=zeroColor.R&&c.G=zeroColor.G&&c.B = zeroColor.B  then
                            yield 0
                        else yield 1
                |]
            yield row
    |]

//辅助函数
let all0 (array : int [])=
    Array.IndexOf(array,1)= -1
let all00 (array: int [] [])=
    let sumAll = 
        array
        |> Array.map ( fun row -> Array.sum row)
        |> Array.sum
    sumAll = 0
let has1 =  all0 >> not
let first1 = 
    Array.findIndex (fun row -> has1 row)
let first1Back array = Array.FindLastIndex(array ,new Predicate<int[]>(has1) )

//将
//[|[|0;1;1|];[|0;1;1|];[|0;1;1|];[|0;1;1|]|] 
//变成
//[|[|0; 0; 0|]; [|1; 1; 1|]; [|1; 1; 1|]|]
//再调用就还原 要求是正方形
let changeIndexPtn (matrix:int [][])=
    [|
        for c in 0..matrix.[0].Length-1 do
            yield
                [|          
                    for r in 0..matrix.Length-1 do
                        yield matrix.[r].[c]
                |]    
    |]     

///获取收缩后矩阵的标志，去除多余空白行与列
///（行开始，行结束，列开始，列结束）
let getShinkMatrixDiscript (matrix:int[][])=
    if all00 matrix then
        (0,1,0,1)
    else
        let rStart = first1 matrix
        let rEnd = first1Back matrix

        let newMatrix =
            [|
                for i in rStart..rEnd do
                    yield matrix.[i]
            |]
        let new2 = newMatrix |> changeIndexPtn

        let cStart =first1 new2
        let cEnd = first1Back new2
        (rStart,rEnd,cStart,cEnd)

let arrangBitmap  (hor:Hor) (ver:Ver)(zeroColor:Color) (bp:Bitmap) =
    let fmatrix= getFeatureMatrix bp zeroColor
    let (rs,re,cs,ce)=getShinkMatrixDiscript fmatrix 
//    printfn "all:%d,%d,%d,%d" rs re cs ce
    let canvas=new Bitmap(bp.Width,bp.Height)
    //目标区域
    let mutable tRs=0
    let mutable tRe=0
    let mutable tCs=0
    let mutable tCe=0
    let dw =ce-cs
    let dh = re-rs
    let bwi =bp.Width-1  //max width index 对应列的最大索引
    let bhi =bp.Height-1 //max height index 对应行的最大索引
    match hor with
    | Hor.C->
        tCs<-(bwi-dw)/2
        tCe<-tCs+dw
    | Hor.L->
        tCs<-0
        tCe<-dw
    | Hor.R->
        tCs<- bwi-dw
        tCe<-bwi

    match ver with
    | Ver.C ->
        tRs<- (bhi-dh)/2
        tRe<- tRs+dh
    | Ver.T ->
        tRs<-0
        tRe<-dh
    | Ver.B ->
        tRs<-bhi-dh
        tRe<-bhi
//    printfn "%d,%d,%d,%d" tRs tRe tCs tCe 
    let deltaR =rs-tRs
    let deltaC =cs-tCs
//    printf "d:%d,%d\n" deltaR deltaC
    for y in rs..re do
        for x in cs..ce do
//            printf "%d,%d\n" (x-deltaC) (y-deltaR)
            canvas.SetPixel(x-deltaC,y-deltaR,bp.GetPixel(x,y))
    canvas

//测试用
let draw (str:string) (canvas:Bitmap) (font:Font) (brush:Brush) (backGroundColor:Color)(ori:OriOptions) hor ver=
    let width =canvas.Width
    let height = canvas.Height
    use g = Graphics.FromImage(canvas)
    //g.TextRenderingHint <- System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
    //其他用这个
    g.TextRenderingHint <- System.Drawing.Text.TextRenderingHint.ClearTypeGridFit
    g.SmoothingMode <- System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    //信封用下面
//    g.TextRenderingHint <- System.Drawing.Text.TextRenderingHint.AntiAliasGridFit
//    g.SmoothingMode <- System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    g.InterpolationMode <- System.Drawing.Drawing2D.InterpolationMode.High;
    g.CompositingQuality <- System.Drawing.Drawing2D.CompositingQuality.HighQuality;

    let mutable rect = new RectangleF(0.0f,0.0f,float32 width,float32 height)
    let mutable data = ""
    //垂直时改变字符串
    match ori with
    | OriOptions.V ->
        data <- str.ToCharArray()
                |> List.ofArray
                |> innerAdd '\n'
                |> List.fold(fun total c -> total+c.ToString()) ""
    | _ -> 
        data <- str
   
    g.DrawString(data,font,brush,rect)
    g.Save()|> ignore
    canvas
    |>arrangBitmap   hor ver backGroundColor


let buildGraphics (canvas:Bitmap) (txtRenderingHint)=
    let g = Graphics.FromImage(canvas)
    g.TextRenderingHint<- txtRenderingHint
    g.SmoothingMode <- System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    g.InterpolationMode <- System.Drawing.Drawing2D.InterpolationMode.High;
    g.CompositingQuality <- System.Drawing.Drawing2D.CompositingQuality.HighQuality;
    g
let preDrawing (g:Graphics) (txt:string) (f) (ori:OriOptions) =
    let sf = new StringFormat()
    match ori with
    | OriOptions.H -> (txt,g,new PointF(0.0f,0.0f),sf)
    | OriOptions.V->
        //垂直时改变字符串
        let txt' =  txt.ToCharArray()
                    |> List.ofArray
                    |> innerAdd '\n'
                    |> List.fold(fun total c -> total+c.ToString()) ""
        sf.Alignment<- StringAlignment.Center
        let sizeF = g.MeasureString(txt,f)
        (txt',g,new PointF(sizeF.Height/2.0f,0.0f),sf)
        

///添加可配置渲染参数
let drawNew (str:string) (canvas:Bitmap) (font:Font) (brush:Brush) (backGroundColor:Color)(ori:OriOptions) hor ver (txtRenderingHint:string)=
    let width =canvas.Width
    let height = canvas.Height
    let hint =
        ref System.Drawing.Text.TextRenderingHint.ClearTypeGridFit 
    System.Drawing.Text.TextRenderingHint.TryParse(txtRenderingHint,hint)|>ignore
    use g =buildGraphics canvas !hint
    let (str',g',centerPoint,stringFormat)=preDrawing g str font ori
    g.DrawString(str',font,brush,centerPoint,stringFormat)
    g.Save()|> ignore
    canvas
    |>arrangBitmap   hor ver backGroundColor

